﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace ys_dec
{
    class ArcYs2
    {
        int key;    //文件头加密密钥
        long pass;
        int count;
        int [] offset;
        int [] length;
        int[] flag;
        string path;//ys2文件位置
        BinaryReader br;
        public ArcYs2(BinaryReader br,string path)
        {
            this.br = br;
            key=0x3D09;
            this.path=path;
        }
        private void Init()
        {
            int id = br.ReadInt32();
            if (id != 0x45325359) throw new Exception("Not a ys2 arc");
            pass = br.ReadInt64();
            count = br.ReadInt32();
            offset = new int[count];
            length = new int[count];
            flag = new int[count];
        }
        private void DecodeHead()
        {
            byte[] buf = new byte[count * 9];
            long decodekey = pass;
            byte dif;
            for (int i = 0; i < buf.Length; i++)
            {
                decodekey *= key;
                decodekey &= 0xFFFFFF;
                dif = (byte)(decodekey >> 16);
                buf[i] = (byte)(br.ReadByte() - dif);
            }
            for (int i = 0; i < count; i++)
            {
                int o = BitConverter.ToInt32(buf, i*9);
                int l = BitConverter.ToInt32(buf, i*9 + 4);
                offset[i] = o;
                length[i] = l;
                flag[i]=buf[i*9 + 8];
            }
            return;
        }
        public void dec()
        {
            Init();
            DecodeHead();
            int headlength=count*9+0x10;
            bool ok = true;
            for (int i = 0; i < count; i++)
            {
                ok = true;
                LzssYs lzss = new LzssYs();
                br.BaseStream.Seek(offset[i] + headlength, SeekOrigin.Begin);
                
                byte[] tag=new byte[2];
                MemoryStream ms = new MemoryStream();

                BinaryWriter bw = new BinaryWriter(ms);
                if (flag[i] == 1 && br.ReadInt32()==0x8)
                {
                    br.BaseStream.Seek(-4, SeekOrigin.Current);
                    byte[] buf = br.ReadBytes(length[i]);
                    MemoryStream msr = new MemoryStream(buf);
                    BinaryReader brt = new BinaryReader(msr);
                    lzss.YsLzss_dec(brt, bw);
                }
                else
                {
                    if (flag[i] == 1)
                    {
                        br.BaseStream.Seek(-4, SeekOrigin.Current);
                        ok = false;
                    }
                    bw.Write(br.ReadBytes(length[i]));
                    Console.Write("dir ");
                }
                ms.Seek(0, SeekOrigin.Begin);
                ms.Read(tag, 0, 2);
                string type;
                int tagi=BitConverter.ToUInt16(tag,0);
                switch (tagi)
                {
                    case 0x4952: type = "wav"; break;
                    case 0x4D42: type = "bmp"; break;
                    case 0x4843: type = "chi"; break;
                    case 0x414D: type = "map"; break;
                    case 0x2284: type = "fnt"; break;
                    default: type = "bin"; break;
                }
                if (!ok) type = "lz";
                ms.Seek(0, SeekOrigin.Begin);
                //if (type == "wav" || type == "bmp") continue;
                FileStream fs = new FileStream(string.Format("{0}\\{1}\\{2:D4}{3}.{1}", path, type, i,flag[i]==0?'a':'b'), FileMode.Create, FileAccess.Write);
                ms.CopyTo(fs);

                fs.Close();
                Console.WriteLine(string.Format("{0} 0x{1:X8} {2} {3} {4}",i,offset[i],length[i],type,flag[i]));
            }
        }

    }
}
